/*
 * FourierTransformFilter.cpp
 *
 *  Created on: 10 Nov 2012
 *      Author: hopey
 */

#include "FourierTransformFilter.h"
#include <iostream>
#include "opencv2/imgproc/imgproc.hpp"
namespace openlid {

FourierTransformFilter::FourierTransformFilter(bool outputMagnitude, bool swapQuandrants) {
	this->outputMagnitude=outputMagnitude;
	this->swapQuandrants=swapQuandrants;

}

FourierTransformFilter::~FourierTransformFilter() {

}

Mat FourierTransformFilter::apply(const Mat& source) {

	if(source.channels()!=1) {
		std::cerr<<"Fourier requires grayscale"<<std::endl;
		return source;
	}

    Mat padded;                            //expand input image to optimal size
    int m = getOptimalDFTSize( source.rows );
    int n = getOptimalDFTSize( source.cols ); // on the border add zero values
    copyMakeBorder(source, padded, 0, m - source.rows, 0, n - source.cols, BORDER_CONSTANT, Scalar::all(0));

    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
    Mat complexI;
    merge(planes, 2, complexI);         // Add to the expanded another plane with zeros

    dft(complexI, complexI);            // this way the result may fit in the source matrix

    // compute the magnitude and switch to logarithmic scale
    // => log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
    split(complexI, planes);                   // planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))

    //At this point we've done the FFT, teh rest is just making a visualisation.

    Mat vis;
    if(outputMagnitude)
    	magnitude(planes[0], planes[1], vis);// planes[0] = magnitude
    else
    	phase(planes[0],planes[1], vis);
    vis += Scalar::all(1);                    // switch to logarithmic scale
    log(vis, vis);

    // crop the spectrum, if it has an odd number of rows or columns
    vis = vis(Rect(0, 0, vis.cols & -2, vis.rows & -2));

    if(swapQuandrants) {
		// rearrange the quadrants of Fourier image  so that the origin is at the image center
		int cx = vis.cols/2;
		int cy = vis.rows/2;

		Mat q0(vis, Rect(0, 0, cx, cy));   // Top-Left - Create a ROI per quadrant
		Mat q1(vis, Rect(cx, 0, cx, cy));  // Top-Right
		Mat q2(vis, Rect(0, cy, cx, cy));  // Bottom-Left
		Mat q3(vis, Rect(cx, cy, cx, cy)); // Bottom-Right

		Mat tmp;                           // swap quadrants (Top-Left with Bottom-Right)
		q0.copyTo(tmp);
		q3.copyTo(q0);
		tmp.copyTo(q3);

		q1.copyTo(tmp);                    // swap quadrant (Top-Right with Bottom-Left)
		q2.copyTo(q1);
		tmp.copyTo(q2);
    }
    normalize(vis, vis, 0, 255, CV_MINMAX);

    //Mat charimg(magI.rows(),magI.cols, CV_8UC1);

    //for(char* src=magI.datastart, dst=charimg.datastart; src!=magI.dataend; )

    vis.convertTo(vis, CV_8UC1);
    return vis;
}

} /* namespace openlid */
